// 最小化的 Bluetooth（BLE）演示程序，使用 `flutter_blue_plus` 插件。
// 功能：扫描设备、连接设备、发现服务/特征、向可写特征分块发送数据、断开连接。
// 目的：提供一个 iOS 可运行的最小 demo（Android 暂时留空）。
//
// 测试环境说明：
// - iOS 构建与真机测试需要在 macOS 上执行（需要 Xcode 与 CocoaPods）。
//   Windows 上无法运行 iOS 真机或执行 `pod install`（会提示 'pod' 未找到）。
// - BLE 操作需要真实硬件，模拟器通常无法提供真实蓝牙功能。
// - 在 Windows 上你仍然可以编辑代码、运行 `flutter pub get`、以及为 Android 添加实现并在 Android 设备上测试。
//
// 注：文件保留为单一 Dart 文件以保持最小可运行示例，便于阅读与移植。

import 'dart:async';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Bluetooth Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  // --- 状态变量说明（中文注释） ---
  // _scanResults: 存放扫描到的设备，key 为设备 id 字符串，value 为 ScanResult
  final Map<String, ScanResult> _scanResults = {};
  // _scanSub: 订阅扫描结果的流，便于停止监听并管理资源
  StreamSubscription<List<ScanResult>>? _scanSub;
  // _scanning: 当前是否正在扫描
  bool _scanning = false;

  // _connectedDevice: 当前已连接的设备实例（如果有）
  BluetoothDevice? _connectedDevice;
  // _writeChar: 发现的第一个可写特征（用于示例发送数据）
  BluetoothCharacteristic? _writeChar;

  @override
  void dispose() {
    _scanSub?.cancel();
    _disconnect();
    super.dispose();
  }

  void _startScan() {
    // 开始扫描：清理旧数据，更新状态并调用插件的 startScan
    _scanResults.clear();
    setState(() {
      _scanning = true;
    });
    // 启动扫描（示例使用 5 秒超时）
    FlutterBluePlus.startScan(timeout: const Duration(seconds: 5));
    // 订阅扫描结果，并把结果保存在 _scanResults 中以便展示
    _scanSub = FlutterBluePlus.scanResults.listen((results) {
      for (var r in results) {
        final id = r.device.id.id;
        _scanResults[id] = r;
      }
      setState(() {});
    });
  }

  void _stopScan() async {
    // 停止扫描并释放订阅
    await FlutterBluePlus.stopScan();
    await _scanSub?.cancel();
    _scanSub = null;
    setState(() {
      _scanning = false;
    });
  }

  Future<void> _connect(ScanResult r) async {
    final device = r.device;
    // 提示连接开始
    _showMessage('Connecting to ${device.name.isNotEmpty ? device.name : device.id.id}');
    try {
      // 发起连接：不同插件/版本 API 可能不同，这里使用动态调用以降低耦合。
      // 如果你的插件版本明确支持 device.connect()，可直接替换为强类型调用。
      await (device as dynamic).connect();
    } catch (e) {
      // 忽略常见连接异常（示例中不做复杂错误处理）
    }
    _connectedDevice = device;
    setState(() {});
    await _discoverServices();
  }

  Future<void> _discoverServices() async {
    // 发现设备服务并查找可写特征（先找到第一个可写特征就返回）
    if (_connectedDevice == null) return;
    final services = await _connectedDevice!.discoverServices();
    for (var s in services) {
      for (var c in s.characteristics) {
        if (c.properties.write || c.properties.writeWithoutResponse) {
          _writeChar = c;
          _showMessage('Found writable characteristic: ${c.uuid}');
          setState(() {});
          return;
        }
      }
    }
    _showMessage('No writable characteristic found');
  }

  Future<void> _disconnect() async {
    // 断开当前已连接设备并清理状态
    if (_connectedDevice != null) {
      try {
        await _connectedDevice!.disconnect();
      } catch (e) {
        // 忽略断开时的异常
      }
      _connectedDevice = null;
      _writeChar = null;
      setState(() {});
    }
  }

  Future<void> _sendDemoBytes({int mtu = 180}) async {
    // 如果没有可写特征则提示并返回
    if (_writeChar == null) {
      _showMessage('No write characteristic available');
      return;
    }
    // 在内存中生成示例数据（例如 1KB 的递增字节）
    final total = 1024;
    final bytes = Uint8List(total);
    for (int i = 0; i < total; i++) {
      bytes[i] = (i % 256);
    }

    // 按 MTU 分块发送（这里简单使用 mtu - 3 作为 chunk 大小估计）
    final chunkSize = mtu - 3; // BLE ATT header 开销估计
    int offset = 0;
    int part = 0;
    try {
      while (offset < bytes.length) {
        final end = (offset + chunkSize < bytes.length) ? offset + chunkSize : bytes.length;
        final chunk = bytes.sublist(offset, end);
        // 使用 withoutResponse 写以提高吞吐（示例），真实场景可根据需求选择
        await _writeChar!.write(chunk, withoutResponse: true);
        offset = end;
        part++;
        // 小延时以避免压垮 BLE 栈
        await Future.delayed(const Duration(milliseconds: 20));
      }
      _showMessage('Sent $part chunks (${bytes.length} bytes)');
    } catch (e) {
      _showMessage('Send failed: $e');
    }
  }

  void _showMessage(String msg) {
    if (!mounted) return;
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg)));
  }

  Widget _buildScanControl() {
    return Row(
      children: [
        ElevatedButton(
          onPressed: _scanning ? _stopScan : _startScan,
          child: Text(_scanning ? '停止' : '开始'),
        ),
        const SizedBox(width: 12),
        ElevatedButton(
          onPressed: _connectedDevice != null ? _disconnect : null,
          child: const Text('Disconnect'),
        ),
        const SizedBox(width: 12),
        ElevatedButton(
          onPressed: _writeChar != null ? () => _sendDemoBytes() : null,
          child: const Text('Send demo bytes'),
        ),
      ],
    );
  }

  Widget _buildDeviceTile(ScanResult r) {
    final name = r.device.name.isNotEmpty ? r.device.name : '<unknown>';
    final id = r.device.id.id;
    final connected = (_connectedDevice != null && _connectedDevice!.id.id == id);
    return ListTile(
      title: Text('$name'),
      subtitle: Text('id: $id  rssi: ${r.rssi}'),
      trailing: ElevatedButton(
        onPressed: connected
            ? null
            : () async {
                await _connect(r);
              },
        child: Text(connected ? 'Connected' : 'Connect'),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final devices = _scanResults.values.toList();
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bluetooth Demo (iOS) - Minimal'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(12.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _buildScanControl(),
            const SizedBox(height: 12),
            Text('Connected: ${_connectedDevice != null ? (_connectedDevice!.name.isNotEmpty ? _connectedDevice!.name : _connectedDevice!.id.id) : 'None'}'),
            const SizedBox(height: 8),
            const Divider(),
            const Text('Discovered devices:'),
            Expanded(
              child: devices.isEmpty
                  ? const Center(child: Text('No devices yet. Start scan.'))
                  : ListView.builder(
                      itemCount: devices.length,
                      itemBuilder: (context, i) => _buildDeviceTile(devices[i]),
                    ),
            ),
          ],
        ),
      ),
    );
  }
}
